package com.geek.gkbgw.web.filter;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * <h1>解决流只能读一次的问题。</h1><br/>
 *
 * <li><h2><a href="https://www.ixigua.com/7007816909366231589?id=7016679125679407649&logTag=7c2c38927bfbbc6db406">详细原因可以点此链接深入了解底层原理。</a></h2></li>
 *
 * @author hmilyylimh
 * ^_^
 * @version 0.0.1
 * ^_^
 * @date 2022-02-27
 */
@Slf4j
public class OnceRequestWrapper extends HttpServletRequestWrapper {

    /** <h2>请求体 body 的 json 字符串内容</h2> **/
    private String jsonBody;

    /** <h2>请求体 body 的 json 字符串的 byte[] 字节数组内容，将来要用于继续传递下去被后面的流读取到</h2> **/
    private byte[] bodyBytes;

    public OnceRequestWrapper(HttpServletRequest request) {
        super(request);
        try {
            // 读取流中的字节数组
            bodyBytes = IOUtils.toByteArray(request.getReader(), "UTF-8");

            // 将流中的字节数组转为字符串形式
            jsonBody = new String(bodyBytes);
        } catch (Exception e) {
            log.error("WebHttpServletRequestWrapper 出错", e);
        }
    }

    /**
     * <h2><h2>获取请求体中的 body 字符串数据。</h2></h2>
     *
     * @throws
     * @param:
     * @return: java.lang.String
     * @author hmilyylimh
     * @date: 2023/9/2
     */
    public String getJsonBody() {
        return jsonBody;
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        final ByteArrayInputStream bais = new ByteArrayInputStream(bodyBytes);
        return new ServletInputStream() {
            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener arg0) {
            }
        };
    }
}